package utils

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/pion/webrtc/v3"
	"go.uber.org/zap"
	"strings"
	"sync"
)

const (
	webrtcCmdOffer      WebsocketCmd = "8001"
	webrtcCmdAnswer                  = "8002"
	webrtcCmdCandidate               = "8003"
	webrtcCmdErr                     = "8004"
	webrtcCmdIceRestart              = "8005"
)

var (
	WebrtcClientMap sync.Map
)

type WebrtcClient struct {
	PeerConn     *webrtc.PeerConnection
	dataChannels map[string]*webrtc.DataChannel
	mu           sync.Mutex
	wsConn       *WsConn
	ctx          context.Context
	cancel       context.CancelFunc
	releaseOnce  sync.Once
}

func (wc *WebrtcClient) start() {
	log := Logger.With(zap.String("remote", wc.wsConn.conn.RemoteAddr().String()))
	wsResponse := wc.wsConn.GetResponse()
	//监听ice变化
	wc.PeerConn.OnICECandidate(func(candidate *webrtc.ICECandidate) {
		Logger.Info("收集到服务端ice", zap.Any("candidate", candidate))
		if candidate != nil {
			wsResponse.WriteJson(webrtcCmdCandidate, candidate.ToJSON())
		}
	})
	wc.PeerConn.OnICEGatheringStateChange(func(state webrtc.ICEGathererState) {
		Logger.Debug("服务端ice状态变化", zap.Any("state", state.String()))
	})
	wc.PeerConn.OnICEConnectionStateChange(func(state webrtc.ICEConnectionState) {
		Logger.Debug("服务端与客户端ice状态变化", zap.Any("state", state.String()))
	})
	//监听Track回调
	wc.PeerConn.OnTrack(func(remote *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
		defer func() {
			if re := recover(); re != nil {
				Logger.Error("监听Track回调", zap.Any("re", re), zap.Stack("stack"))
			}
		}()
		log.Debug("监听Track回调", zap.String("id", remote.ID()))
		if webrtcTrackHandle != nil {
			webrtcTrackHandle(remote, receiver, wsResponse)
		}
	})
	//监听DataChannel回调
	wc.PeerConn.OnDataChannel(func(d *webrtc.DataChannel) {
		d.OnMessage(func(msg webrtc.DataChannelMessage) {
			log.Debug("收到DataChannel消息", zap.String("label", d.Label()), zap.ByteString("data", msg.Data))
			if webrtcDataChannelMsgHandle != nil {
				webrtcDataChannelMsgHandle(d.Label(), msg.Data)
			}
		})
	})
	//监听连接状态变化
	wc.PeerConn.OnConnectionStateChange(func(state webrtc.PeerConnectionState) {
		switch state {
		case webrtc.PeerConnectionStateConnecting:
			log.Info("webrtc 状态变化", zap.String("state", "连接中..."))
		case webrtc.PeerConnectionStateConnected:
			log.Info("webrtc 状态变化", zap.String("state", "连接成功！"))
		case webrtc.PeerConnectionStateDisconnected:
			log.Debug("webrtc 状态变化", zap.String("state", "连接断开，尝试 ICE restart"))
			//go wc.iceRestart() // 手动触发 ICE restart
		case webrtc.PeerConnectionStateFailed:
			log.Debug("webrtc 状态变化", zap.String("state", "连接失败，关闭webrtcClient并清理资源"))
			wc.Release()
		case webrtc.PeerConnectionStateClosed:
			log.Debug("webrtc 状态变化", zap.String("state", "连接已关闭"))
		default:
			log.Debug("webrtc 状态变化", zap.String("其他state", state.String()))
		}
	})
	//监听websocket或webrtc的context.done
	go func() {
		err := Cover(func() {
			<-wc.ctx.Done()
			wc.Release()
		})
		if err != nil {
			Logger.Error("监听websocket或webrtc的context.done", zap.Error(err))
		}
	}()
}

func (wc *WebrtcClient) Release() {
	wc.releaseOnce.Do(func() {
		wc.mu.Lock()
		defer func() {
			wc.cancel()
			wc.mu.Unlock()
		}()
		//关闭所有dataChannel
		if wc.dataChannels != nil {
			for label, dc := range wc.dataChannels {
				Logger.Debug("webrtc 关闭dataChannel", zap.String("label", label))
				_ = dc.Close()
			}
			wc.dataChannels = nil
		}
		//关闭peerConn
		if wc.PeerConn != nil {
			Logger.Debug("webrtc 关闭PeeConn")
			_ = wc.PeerConn.Close()
			wc.PeerConn = nil
		}
		//移除全局webrtcClient
		Logger.Debug("webrtc 关闭后并从全局webrtc连接移除")
		WebrtcClientMap.Delete(wc.wsConn.connId)
	})
}

func (wc *WebrtcClient) iceRestart() {
	wc.mu.Lock()
	if wc.PeerConn == nil {
		wc.mu.Unlock()
		return // PeerConnection 已关闭
	}
	wc.mu.Unlock()

	// 创建 ICE restart Offer
	offer, err := wc.PeerConn.CreateOffer(&webrtc.OfferOptions{ICERestart: true})
	if err != nil {
		Logger.Error("webrtc-iceRestart-创建Offer失败", zap.Error(err))
		return
	}
	if err = wc.PeerConn.SetLocalDescription(offer); err != nil {
		Logger.Error("webrtc-iceRestart-设置本地描述失败", zap.Error(err))
		return
	}
	//通知客户端
	wc.wsConn.GetResponse().WriteJson(webrtcCmdOffer, offer)
}

// WebrtcClientGet 获取或创建websocket关联的webrtcClient
func WebrtcClientGet(wsConn *WsConn, create ...bool) (wc *WebrtcClient, err error) {
	wcInter, ok := WebrtcClientMap.Load(wsConn.connId)
	if ok {
		return wcInter.(*WebrtcClient), nil
	}
	if len(create) == 0 || !create[0] {
		//不需要创建
		return nil, fmt.Errorf("not found webrtc peer_conn")
	}
	//获取turn配置
	turnAddr := strings.Split(Ini_Str("turn.addr"), ",")
	iceServer := webrtc.ICEServer{URLs: turnAddr}
	if username := Ini_Str("turn.user"); username != "" {
		iceServer.Username = username
	}
	if credential := Ini_Str("turn.pwd"); credential != "" {
		iceServer.Credential = credential
		iceServer.CredentialType = webrtc.ICECredentialTypePassword
	}

	//创建webrtc信道
	config := webrtc.Configuration{
		ICEServers: []webrtc.ICEServer{iceServer},
	}
	peerConn, err := webrtc.NewPeerConnection(config)
	if err != nil {
		Logger.Error("创建webrtc PeerConnection失败", zap.Error(err))
		return
	} else {
		Logger.Info("创建webrtc成功", zap.Any("iceServer", iceServer))
	}
	ctx, cancel := context.WithCancel(wsConn.ctx)
	wc = &WebrtcClient{
		PeerConn:     peerConn,
		dataChannels: make(map[string]*webrtc.DataChannel),
		wsConn:       wsConn,
		ctx:          ctx,
		cancel:       cancel,
	}
	wc.start()
	Logger.Info("webrtc-创建新的peerConn，并保存到全局webrtc连接")
	WebrtcClientMap.Store(wsConn.connId, wc)
	return wc, nil
}

// WebrtcSdpOfferHandle 接受offer请求返回answer
func WebrtcSdpOfferHandle(ctx context.Context, msg []byte, response *WebsocketResponse) {
	wc, err := WebrtcClientGet(response.WsConn, true)
	if err != nil {
		response.WriteErr(webrtcCmdErr, err)
		return
	}
	//解析offer
	var offer webrtc.SessionDescription
	if err = json.Unmarshal(msg, &offer); err != nil {
		Logger.Error("webrtc处理offer-解析offer", zap.Error(err), zap.ByteString("msg", msg))
		response.WriteErr(webrtcCmdErr, err)
		return
	}
	if err = wc.PeerConn.SetRemoteDescription(offer); err != nil {
		Logger.Error("webrtc处理offer-SetRemoteDescription", zap.Error(err), zap.ByteString("msg", msg))
		response.WriteErr(webrtcCmdErr, err)
		return
	}
	//创建answer
	answer, err := wc.PeerConn.CreateAnswer(nil)
	if err != nil {
		Logger.Error("webrtc处理offer-CreateAnswer", zap.Error(err))
		response.WriteErr(webrtcCmdErr, err)
		return
	}
	if err = wc.PeerConn.SetLocalDescription(answer); err != nil {
		Logger.Error("webrtc处理offer-SetLocalDescription", zap.Error(err), zap.ByteString("msg", msg))
		response.WriteErr(webrtcCmdErr, err)
		return
	}

	response.WriteJson(webrtcCmdAnswer, answer)
}

// WebrtcSdpAnswerHandle 接受answer应答
func WebrtcSdpAnswerHandle(ctx context.Context, msg []byte, response *WebsocketResponse) {
	wc, err := WebrtcClientGet(response.WsConn)
	if err != nil {
		response.WriteErr(webrtcCmdErr, err)
		return
	}
	//解析answer
	var answer webrtc.SessionDescription
	if err = json.Unmarshal(msg, &answer); err != nil {
		Logger.Error("webrtc接受answer应答-解析answer", zap.Error(err), zap.ByteString("msg", msg))
		response.WriteErr(webrtcCmdErr, err)
		return
	}
	if err = wc.PeerConn.SetRemoteDescription(answer); err != nil {
		Logger.Error("webrtc接受answer应答-SetRemoteDescription", zap.Error(err), zap.ByteString("msg", msg))
		response.WriteErr(webrtcCmdErr, err)
		return
	}
	return
}

// WebrtcCandidateHandle 交换ice
func WebrtcCandidateHandle(ctx context.Context, msg []byte, response *WebsocketResponse) {
	wc, err := WebrtcClientGet(response.WsConn)
	if err != nil {
		response.WriteErr(webrtcCmdErr, err)
		return
	}
	if len(msg) == 0 {
		Logger.Info("webrtc客户端收集ICE候选完成")
		return
	}
	var candidate webrtc.ICECandidateInit
	if err = json.Unmarshal(msg, &candidate); err != nil {
		Logger.Error("webrtc交换ice-解析answer", zap.Error(err), zap.ByteString("msg", msg))
		response.WriteErr(webrtcCmdErr, err)
		return
	}
	if err = wc.PeerConn.AddICECandidate(candidate); err != nil {
		Logger.Error("webrtc交换ice-AddICECandidate", zap.Error(err), zap.ByteString("msg", msg))
		response.WriteErr(webrtcCmdErr, err)
		return
	}
}

type WebrtcTrackHandleFn func(*webrtc.TrackRemote, *webrtc.RTPReceiver, *WebsocketResponse)

type WebrtcDataChannelMsgHandleFn func(label string, msg []byte)

var (
	webrtcTrackHandle WebrtcTrackHandleFn

	webrtcDataChannelMsgHandle WebrtcDataChannelMsgHandleFn
)

func WebrtcServiceInit(trackHandle WebrtcTrackHandleFn, dataChannelHandle WebrtcDataChannelMsgHandleFn) {
	webrtcTrackHandle = trackHandle
	webrtcDataChannelMsgHandle = dataChannelHandle
	WebsocketAddHandle(webrtcCmdOffer, WebrtcSdpOfferHandle, "webrtc的offer请求")
	WebsocketAddHandle(webrtcCmdAnswer, WebrtcSdpAnswerHandle, "webrtc的answer请求")
	WebsocketAddHandle(webrtcCmdCandidate, WebrtcCandidateHandle, "webrtc的ice交换请求")
}
